// Cowing, Hawkins, Pugh
// Project 2C
// BattleManager.cpp

#include <iostream>
#include <fstream>
#include <ctime>
#include <cctype>
#include <iomanip>
#include "BattleManager.h"
using namespace std;

BattleManager::BattleManager(Character& p){
	cPlayer = &p;
	// assign short names
	P_MinDam = p.getWeapon().getMinimumDamage();
	P_MaxDam = p.getWeapon().getMaximumDamage();
	P_CritMult = p.getWeapon().getCriticalMultiplier();
	P_CritMin = p.getWeapon().getCriticalMinimum();
	P_StrMod = p.getStrMod();
	LoadMonsters();				// read from file
	srand(time(NULL));			// seed random number generator
	monster = mMonsterList[rand()%numof_monsters];
	firstRound = 0;
	
}//end constructor

void ~BattleManager::BattleManager(){
	delete [] mMonsterList;
	delete cPlayer;
}
 
void BattleManager::DispStats(){
	 if(!firstRound){
		if(result = MISS)
			cout<<"MISS\n\n";
		else if(result = CRITICAL_HIT)
			cout<<"CRITICAL HIT\n\n";
		else
			cout<<"HIT\n\n";
	 }

	cout << "BATTLE CONDITION\n\n"
		 << "Player" 		<< '\t' << 	monster.name << '\n';
		 << cPlayer->hitPoints << '\t' <<  monster.hit_points <<"\tHit Points\n"
		 << P_MinDam 	<< '\t' << 	monster.minimum_damage << "\tWeapon Minimum Damage\n"
		 << P_MaxDam 	<< '\t' << 	monster.maximum_damage << "\tWeapon Maximum Damage\n"
		 << cPlayer->strength <<'\t' << monster.strength << "\tStrength\n"
		 << cPlayer->dexterity <<'\t' << monster.dexterity << "\tDexterity\n"
		 << cPlayer->wisdom << '\t' << monster.wisdom << "\tWisdom\n"

 }//end dispStats

				 
CombatResult BattleManager::fight(){
	char combat_opt;							// user input var.
	bool bad_input = true;
	bool fight_status = true;
	const bool	playerAttack = true;
	const bool  CritHit = true;
	firstRound = 0;

	while(fight_status){						// some calc. needed to modify this test var.
		while(bad_input){
			system("cls");
			DispStats();						// output player/monster stats before selection
			cout<<"\n\n"
				<<"A.  Attack\n"
				<<"I.  Intimidate\n"
				<<"R.  Run\n"
				<<"S.  Study Opponent\n\n"
				<<"Select a combat option: ";
			cin.get(combat_opt);
			switch(tolower(combat_opt)){
				case 'a': 
					result = attack(!CritHit, playerAttack)
					bad_input = false;
					break;

				case 'i': 
					if (intimidate()) {
						cPlayer->hitPoints ++;
						return MONSTER_SCARED;
					}
					else
						result = attack(!CritHit, !playerAttack);
					bad_input = false;
					break;

				case 'r': 
					if(run())
						return PLAYER_ESCAPED;
					else
						result = attack(!CritHit, !playerAttack);
					bad_input = false;
					break;

				case 's': 
					if (studyOpp())
						result = attack(CritHit, playerAttack);
					else
						result = attack(!CritHit, !playerAttack);
					bad_input = false;
					break;

				default:
					bad_input = true;			
			}//close switch
		}//close while(bad_input)

	if(monster.hit_points <= 0)
		return MONSTER_DEAD;
	if(cPlayer->hitPoints <= 0)
		return PLAYER_DEAD;

	if (MONSTER_DEAD || PLAYER_DEAD || MONSTER_SCARED || PLAYER_ESCAPED)
		fight_status = false;
	firstRound  = false;
	}//close while(fight_status)
}//end fight
			
AttackResult BattleManager::attack(const bool critHit, const bool playerAttack){
	int	damage=0;
	int PlayerRoll = rollDie();
	int MonsterRoll = rollDie();
	AttackResult stat;
	
	if(playerAttack){	
		if(PlayerRoll >= P_CritMin || CritHit == true){
			for(int i = 1; i < P_CritMult; i++)
				damage += genRandNum(P_MinDam, P_MaxDam) + P_StrMod;
			stat = CRITICAL_HIT;
		}		
		else if(PlayerRoll + baseAttack + P_StrMod >= monster.armor_bonus){
			damage = genRandNum(P_MinDam, P_MaxDam) + P_StrMod;				
			stat = HIT;
		}
		else
			return MISS;
		monster.hit_points -= damage;
	}//close if(playerAttack)

	else{

	   if(MonsterRoll >= monster.critical_minimum){
			for(int i = 1; i < monster.critical_multiplier; i++)
				damage += genRandNum(monster.minimum_damage, monster.maximum_damage) + monster.strength;
			 stat = CRITICAL_HIT;
	   }

		else if(MonsterRoll + baseAttack + monster.strength >= monster.armor_bonus){
				damage = genRandNum(monster.minimum_damage, monster.maximum_damage) + monster.strength;
				
				stat = HIT;
		}
		else
				return MISS;

		cPlayer->hitPoints -= damage;

	}//close else
	return stat;

}// end attack

void BattleManager::LoadMonsters(){
	ifstream MonsterFile("monsters.txt");
	if(!MonsterFile) throw NoMonsterFile_E();
	infile >> numof_monsters;
	mMonsterList = new Monster[numof_monsters];
	for(int i = 0; i < numof_monsters; i++){
		MonsterFile >> mMonsterList[i].name;
		MonsterFile >> mMonsterList[i].strength;
		MonsterFile >> mMonsterList[i].dexterity;
		MonsterFile >> mMonsterList[i].constitution;
		MonsterFile >> mMonsterList[i].wisdom;
		MonsterFile >> mMonsterList[i].charisma;
		MonsterFile >> mMonsterList[i].weapon_name;
		MonsterFile >> mMonsterList[i].minimum_damage;
		MonsterFile >> mMonsterList[i].maximum_damage;
		MonsterFile >> mMonsterList[i].critical_minimum;
		MonsterFile >> mMonsterList[i].critical_multiplier;
		MonsterFile >> mMonsterList[i].armor_name;
		MonsterFile >> mMonsterList[i].armor_bonus;
		MonsterFile >> mMonsterList[i].armor_penalty;
		MonsterFile >> mMonsterList[i].maximum_dexterity;
		MonsterFile >> mMonsterList[i].base_attack_bonus;
		MonsterFile >> mMonsterList[i].hit_points;
	}
	MonsterFile.close();
}// end LoadMonsters

int BattleManager::genRandNum(int low, int high){return rand() % high + low;}

int BattleManager::rollDie(){return rand() % 20 + 1;}

bool BattleManager::run(){
	int PlayerRoll = rollDie() + cPlayer->getDexMod() + cPlayer->getArmor().getPenalty();
	int MonsterRoll = rollDie() + monster.dexterity + monster.wisdom;	
	if(PlayerRoll >= MonsterRoll)
		return true;
	else
		return false;
}
bool BattleManager::studyOpp(){
	int PlayerRoll = rollDie() + cPlayer->getWisMod();
	int MonsterRoll = rollDie() + monster.dexterity() + monster.armor_penalty;	
	if(PlayerRoll >= MonsterRoll)
		return true;
	else
		return false;
}

bool BattleManager::intimidate(){
	int PlayerRoll = rollDie() + cPlayer->getChaMod();
	int MonsterRoll = rollDie() + monster.wisdom();	
	if(PlayerRoll >= MonsterRoll)
		return true;
	else
		return false;
}